#include "lib/ds/list.h"
#include "lib/global.h"
#include "interrupt/interrupt.h"

void list_init(struct list* list){
    list->head.prev = NULL;
    list->head.next = &list->tail;
    list->tail.prev = &list->head;
    list->tail.next = NULL;
}

void list_insert_before(struct list_elem *before, struct list_elem *elem){
    enum intrStates old_state = DisableIntr();
    elem->next = before;
    elem->prev = before->prev;
    before->prev->next = elem;
    before->prev = elem;
    intr_set_status(old_state);
}

void list_push_front(struct list *list, struct list_elem *elem) 
{
    list_insert_before(&list->head.next, elem);
}

void list_push_back(struct list *list, struct list_elem *elem)
{
    list_insert_before(&list->tail, elem);
}

void list_remove(struct list_elem *elem) {
    enum intrStates old_state = DisableIntr();
    elem->prev->next = elem->next;
    elem->next->prev = elem->prev;
    intr_set_status(old_state);
}

struct list_elem *list_pop_front(struct list *list){
    if(list_empty(list)){
        return NULL;
    }
    struct list_elem* res = list->head.next;
    list_remove(res);
    return res;
}

struct list_elem *list_pop_back(struct list *list) {
    if(list_empty(list)){
        return NULL;
    }
    struct list_elem* res = list->tail.prev;
    list_remove(res);
    return res;
}

uint32_t list_empty(struct list *list) {
    return list->head.next == &list->tail;
}

uint32_t list_size(struct list *list) {
    uint32_t size = 0;
    struct list_elem *elem = list_begin(list);
    while(elem != list_end(list)){
        size++;
        elem = list_next(elem);
    }
    return size;
}

struct list_elem *list_begin(struct list *list) {
    return list->head.next;
}

struct list_elem *list_end(struct list *list) {
    return &list->tail;
}

struct list_elem *list_next(struct list_elem *elem) {
    return elem->next;
}

struct list_elem *list_prev(struct list_elem *elem) {
    return elem->prev;
}

struct list_elem *list_traversal(struct list *list, ListFunction func, int arg) {
    struct list_elem *elem = list_begin(list);
    if(list_empty(list)){
        return NULL;
    }
    while(elem != list_end(list)){
        if(func(elem, arg)){
            return elem;
        }
        elem = list_next(elem);
    }
    return NULL;
}

uint32_t elem_find(struct list *list, struct list_elem *obj_elem) {
    struct list_elem *elem = list_begin(list);
    if(list_empty(list)){
        return 0;
    }
    while(elem != list_end(list)){
        if(elem == obj_elem){
            return 1;
        }
        elem = list_next(elem);
    }
    return 0;
}
